// 标准树接口
export type ITreeData = {
  title: string;
  key: string;
  children?: ITreeData;
  [key: string]: unknown;
}[];
/**
 * 普通树结构格式化成标准树结构，
 * @param data 原生数组
 * @param key key对应的字段
 * @param treeNodeId id对的字段和数组字段
 * @param treeNodeParentId parentId对应的字段和数据字段
 */
export function formatTreeData({
  data,
  key,
  title,
  childrenKey,
  treeNodeId,
  treeNodeParentId,
  format,
}: {
  data: object[];
  key: string;
  title: string;
  childrenKey: string;
  treeNodeId?: [string, string];
  treeNodeParentId?: [string, string];
  format?: (data: ITreeData[number]) => void;
}): ITreeData | undefined {
  if (data?.length && Array.isArray(data)) {
    data.forEach((item: any) => {
      if (item.title === undefined) {
        item.title = item[title];
      }
      if (item.key === undefined) {
        item.key = item[key];
      }
      if (treeNodeId) {
        item[treeNodeId[0]] = item[treeNodeId[1]];
      }
      if (treeNodeParentId) {
        item[treeNodeParentId[0]] = item[treeNodeParentId[1]];
      }
      if (item[childrenKey] || item?.children) {
        item.children = formatTreeData({
          data: item[childrenKey] || item.children,
          key,
          title,
          childrenKey,
          treeNodeId,
          treeNodeParentId,
          format,
        });
      }
      format?.(item);
    });
    return data as ITreeData;
  } else {
    return [];
  }
}
/**
 * 修改树结构数据
 * @param props
 *    key 查找的key, 默认为key
 *    keyValue 查找key对应的value
 *    type 操作类型
 *    treeData 需要更新得数据
 *    data 更新得数据
 */
function updateTreeData(props: {
  key?: string;
  keyValue: string;
  type: 'add';
  treeData?: ITreeData;
  data?: ITreeData | ITreeData[number];
  isRoot?: boolean;
}): ITreeData;
function updateTreeData(props: {
  key?: string;
  keyValue: string;
  type: 'delete';
  treeData?: ITreeData;
}): ITreeData;
function updateTreeData(props: {
  key?: string;
  keyValue: string;
  type: 'update';
  treeData?: ITreeData;
  data: ITreeData[number];
}): ITreeData;
function updateTreeData(props: {
  key?: string;
  keyValue: string;
  type: 'add' | 'delete' | 'update';
  treeData?: ITreeData;
  data?: ITreeData | ITreeData[number];
  isRoot?: boolean;
}): ITreeData {
  if (!props.treeData?.length) {
    return [];
  }
  if (props.type == 'add' && !props.data) {
    return props.treeData;
  }
  if (props.isRoot && props.type == 'add' && props.data) {
    const newData = [...props.treeData];
    newData.push(...(Array.isArray(props.data) ? props.data : [props.data]));
    return newData;
  }
  if (props.treeData?.length) {
    let index: number | undefined,
      find = false;
    const key = props.key || 'key';
    const treeData = props.treeData.map((item, i) => {
      if (find) {
        return item;
      } else {
        if (item[key] == props.keyValue) {
          find = true;
          index = i;
          if (props.type === 'add') {
            const data = Array.isArray(props.data) ? props.data : [props.data];
            const children = item.children || [];
            data.forEach((item) => {
              if (!children.find((cItem) => cItem.key == item!.key)) {
                children.push(item!);
              }
            });
            return {
              ...item,
              children,
            };
          }
          if (props.type === 'update') {
            return {
              ...item,
              ...(props.data || {}),
            };
          }
          return item;
        } else {
          if (item.children) {
            return {
              ...item,
              //@ts-ignore
              children: updateTreeData({ ...props, treeData: item.children } as typeof props),
            };
          } else {
            return item;
          }
        }
      }
    });
    if (props.type === 'delete' && index != undefined) {
      treeData.splice(index, 1);
    }
    return treeData as ITreeData;
  } else {
    return undefined as unknown as ITreeData;
  }
}
export { updateTreeData };

/**
 * 查找树结构的指定数据
 * @param props
 *    key 查找的key, 默认为key
 *    keyValue 查找key对应的value
 *    treeData 需要查找的数据
 */
export function findTreeNode(props: {
  key?: string;
  keyValue: string;
  treeData?: ITreeData;
}): ITreeData[number] | undefined {
  if (props.treeData?.length) {
    const key = props.key || 'key';
    const data = props.treeData.find((item) => item[key] == props.keyValue);
    if (data) {
      return data;
    } else {
      return findTreeNode({
        ...props,
        treeData: props.treeData
          .map((item) => item.children)
          .flat()
          .filter((item) => !!item) as ITreeData,
      });
    }
  } else {
    return undefined;
  }
}

/**
 * 查找树结构的多条指定数据
 * @param props
 *    key 查找的key, 默认为key
 *    keyValue 查找key对应的value
 *    treeData 需要查找的数据
 * 返回顺序和keyValue保持一致
 */
export function findTreeNodes(props: {
  key?: string;
  keyValue: string[];
  treeData?: ITreeData;
}): ITreeData {
  if (!props.treeData?.length) {
    return [];
  }
  const nodeData = getTreeNodes({
    ...props,
    treeData: props.treeData!,
    key: props.key || 'key',
    result: {},
  });
  return props.keyValue.map((item) => nodeData[item]);
}
function getTreeNodes(props: {
  key: string;
  keyValue: string[];
  treeData: ITreeData;
  result: object;
}) {
  if (props.keyValue.length === Object.keys(props.result).length) {
    return props.result;
  }
  for (let i = 0, len = props.treeData.length; i < len; i++) {
    const item = props.treeData[i];
    const findeValue = props.keyValue.find((value) => value == item[props.key]);
    if (findeValue !== undefined) {
      props.result[(item[props.key] as string).toString()] = item;
      if (props.keyValue.length === Object.keys(props.result).length) {
        return props.result;
      }
    }
    if (item?.children) {
      getTreeNodes({
        ...props,
        treeData: item.children,
      });
    }
  }
  return props.result;
}
/**
 * 查找指定节点的所有父级节点
 * @param props
 *   key 查找的key, 默认为key
 *   keyValue 查找key对应的value
 *   resultSelf 是否在最后一项返回自己
 *   treeData 需要查找的数据
 */

export function findTreeParents(props: {
  key?: string;
  keyValue: string;
  treeData?: ITreeData;
  resultSelf?: boolean;
  result?: ITreeData;
}) {
  if (!props.treeData?.length) {
    return [];
  }
  const result = props.result || [];
  const key = props.key || 'key';
  if (props.treeData?.length) {
    const data = props.treeData.find((item) => item[key] == props.keyValue);
    if (!data) {
      let parentNodes;
      const isfind = props.treeData.some((item) => {
        if (item.children) {
          parentNodes = findTreeParents({
            ...props,
            treeData: item.children,
            result: result.concat(item),
          });
          return !!parentNodes?.length;
        } else {
          return false;
        }
      });
      if (isfind) {
        return parentNodes;
      } else {
        return [];
      }
    } else {
      return props.resultSelf ? result.concat(data) : result;
    }
  } else {
    return [];
  }
}
/**
 * 树结构转换成普通数组
 * @param treeData
 * @returns
 */
export function treeDataToArray(treeData?: ITreeData, result: ITreeData = []): ITreeData {
  if (!treeData) {
    return [];
  }
  const tree = Array.isArray(treeData) ? treeData : [treeData];
  result.push(...tree);
  tree
    .filter((item) => item?.children?.length)
    .forEach((item) => {
      treeDataToArray(item.children, result);
    });
  return result;
}
/**
 * 根据层级格式化数据
 * treeData 原始数据
 * format 格式化函数
 */

export function treeDataLevelFormat({
  treeData,
  format,
  parents = [],
}: {
  treeData?: ITreeData;
  format: (item: ITreeData[number], parents: ITreeData[number][]) => object;
  parents?: ITreeData[number][]; // 父级节点列表
}): ITreeData {
  if (treeData?.length) {
    return treeData.map((item) => {
      return {
        ...item,
        ...(format(item, parents) || {}),
        children: treeDataLevelFormat({
          treeData: item.children,
          format,
          parents: parents.concat(item),
        }),
      } as unknown as ITreeData;
    }) as unknown as ITreeData;
  } else {
    return treeData!;
  }
}

// 根据'$' 切割配置字段对应的值
export const getFieldKey = (value?: string, number: 0 | 1 = 0) => {
  if (!value) {
    return '0';
  }
  if (value.includes('$')) {
    return value.split('$')[number];
  } else {
    return value;
  }
};
